// Package request 提供HTTP请求功能，支持文件上传等特性
package request

import (
	"bytes"
	"crypto/tls"
	"io"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path"
	"time"

	"gitee.com/tuboyou/c2/u2"
)

// PostMultipart 执行带文件上传的POST请求
//
// 参数：
//
//	name - 请求名称
//	Url - 请求URL
//	query - URL查询参数
//	body - 表单字段
//	file - 要上传的文件，key为字段名，value为文件路径
//	headers - 请求头
//	timeout - 超时时间（毫秒）
//	error - 初始错误信息
//
// 返回值：
//
//	Response - 请求的响应结果
//
// 注意：
//
//  1. 会自动设置Content-Type为multipart/form-data
//  2. 支持同时上传多个文件
//  3. 如果文件打开失败，会返回包含错误信息的Response
//  4. 默认忽略TLS证书验证
//
// 示例：
//
//	query := map[string]string{"param1": "value1"}
//	body := map[string]string{"field1": "value1"}
//	file := map[string]string{"file1": "/path/to/file.txt"}
//	headers := map[string]string{"Authorization": "Bearer token"}
//	resp := PostMultipart("test", "https://example.com/upload", query, body, file, headers, 5000, nil)
func PostMultipart(name, Url string, query, body, file, headers map[string]string, timeout int, error error) Response {
	r := &Request{Name: name, Method: "POST", Headers: headers, Timeout: timeout, error: error, Query: query}
	if error != nil {
		return r.Run()
	}
	u, err := url.Parse(Url)
	if err != nil {
		r.error = err
		return r.Run()
	}
	r.Url = u
	buf := new(bytes.Buffer)
	w := multipart.NewWriter(buf)
	for k, v := range body {
		w.WriteField(k, v)
	}
	for k, v := range file {
		file, err := os.Open(v)
		if err != nil {
			r.error = err
			return r.Run()
		}
		defer file.Close()

		fw, err := w.CreateFormFile(k, path.Base(v))
		if err != nil {
			r.error = err
			return r.Run()
		}
		if _, err := io.Copy(fw, file); err != nil {
			r.error = err
			return r.Run()
		}
	}
	defer w.Close()
	r.Body = buf.String()
	if r.Query != nil {
		val := r.Url.Query()
		for k, v := range r.Query {
			val.Set(k, v)
		}
		r.Url.RawQuery = val.Encode()
	}
	hreq, err := http.NewRequest("POST", r.Url.String(), buf)
	if err != nil {
		r.error = err
		return r.Run()
	}
	if r.Headers == nil {
		r.Headers = make(map[string]string)
	}
	r.Headers["Content-Type"] = w.FormDataContentType()

	for k, v := range r.Headers {
		hreq.Header.Set(k, v)
	}

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}

	stTime := u2.TimeNow().UnixMilli()
	client := &http.Client{Timeout: time.Second * time.Duration(r.Timeout) / 1000, Transport: tr}
	resp, err := client.Do(hreq)
	return newResponseByHttp(-4, resp, stTime, r, err)
}
